import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
import {
  getUserProfile,
  LoginForm,
  postLogin,
  postRegister,
  RegisterForm,
  User
} from '../services/auth'

/**
 * 定义 vuex 全局状态的类型
 */
export interface State {
  accessToken: string | null
  currentUser: User | null
}

export const key: InjectionKey<Store<State>> = Symbol('vuex')

/**
 * 保证 useStore 返回带类型声明的 store
 *
 * @see https://next.vuex.vuejs.org/zh/guide/typescript-support.html
 */
export function useStore() {
  return baseUseStore(key)
}

/**
 * 包装 JSON.parse 并处理可能的异常
 */
function safeJsonParse(value: string | null) {
  if (value == null) {
    return null
  }
  try {
    return JSON.parse(value)
  } catch (err) {
    return null
  }
}

/**
 * 创建 vuex 全局状态 store
 *
 * @see https://next.vuex.vuejs.org/zh/
 */
export default createStore<State>({
  state: {
    /**
     * 储存 accessToken，同时保存在 localStorage 中
     */
    accessToken: localStorage.getItem('accessToken'),
    /**
     * 储存当前用户信息，也保存在 localStorage 中
     */
    currentUser: safeJsonParse(localStorage.getItem('currentUser'))
  },
  mutations: {
    /**
     * 将 accessToken 设置到 store 与 localStorage
     */
    setAccessToken(state, token) {
      state.accessToken = token
      localStorage.setItem('accessToken', token)
    },
    /**
     * 从 store 与 localStorage 中移除移除 accessToken
     */
    removeAccessToken(state) {
      state.accessToken = null
      localStorage.removeItem('accessToken')
    },
    /**
     * 将当前用户信息设置到 store 与 localStorage
     */
    setUser(state, user) {
      state.currentUser = user
      localStorage.setItem('currentUser', JSON.stringify(user))
    },
    /**
     * 从 store 与 localStorage 中移除当前用户信息
     */
    removeUser(state) {
      state.currentUser = null
      localStorage.removeItem('currentUser')
    }
  },
  actions: {
    /**
     * 登录，请求登录 API 并设置 accessToken 与当前用户信息
     */
    async login({ commit }, data: LoginForm) {
      const res = await postLogin(data)
      commit('setAccessToken', res.data.accessToken)
      commit('setUser', res.data.user)
    },
    /*
     * 注册，请求注册 API 并设置 accessToken 与当前用户信息
     */
    async register({ commit }, data: RegisterForm) {
      const res = await postRegister(data)
      commit('setAccessToken', res.data.accessToken)
      commit('setUser', res.data.user)
    },
    /**
     * 请求 API 并刷新当前用户信息
     */
    async refreshUserData({ commit }) {
      const res = await getUserProfile()
      commit('setUser', res.data)
    },
    /**
     * 登出，移除 accessToken 与当前用户信息
     */
    async logout({ commit }) {
      commit('removeAccessToken')
      commit('removeUser')
    }
  }
})
